package com.xiaoyu.lanling.util;

import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.text.TextUtils;
import android.util.Log;

import com.xiaoyu.base.app.AppContext;
import com.xiaoyu.lanling.log.AppLogClient;

import in.srain.cube.util.UTUtil;
import in.srain.cube.util.log.LogEvent;

public class MP3PlayerUtils {

    private MediaPlayer mMediaPlayer;
    private AudioManager mAudioManager;
    private boolean mIsPlaying = false;
    private String mPath;
    private AudioManager.OnAudioFocusChangeListener listener = focusChange -> {
    };

    public interface OnStatusListener {

        void onCompletion(MediaPlayer mp);

        void OnPrepared(MediaPlayer mp);

        void OnPlaying(MediaPlayer mp);

        void OnError(String what, String extra);
    }

    private static class InstanceHolder {
        private static MP3PlayerUtils INSTANCE = new MP3PlayerUtils();
    }

    public static MP3PlayerUtils getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private MP3PlayerUtils() {
        initPlayer();
    }

    private void initPlayer() {
        reset();

        if (mMediaPlayer == null) {
            mMediaPlayer = new MediaPlayer();
        }
        if (mAudioManager == null) {
            mAudioManager = (AudioManager) AppContext.getContext().getSystemService(Context.AUDIO_SERVICE);
        }
    }

    public boolean start(String path, MediaPlayer.OnCompletionListener onCompletionListener) {
        initPlayer();
        logEventForAudio("start", path, "");
        try {
            int streamType = AudioManager.STREAM_MUSIC;
            mAudioManager.requestAudioFocus(listener, streamType, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
            mMediaPlayer.setAudioStreamType(streamType);
            mMediaPlayer.setDataSource(path);
            mMediaPlayer.setOnPreparedListener(mediaPlayer -> {
                mMediaPlayer.start();
                logEventForAudio("prepared", path, "");
            });
            mMediaPlayer.setOnCompletionListener(mp -> {
                if (onCompletionListener != null) {
                    onCompletionListener.onCompletion(mp);
                }
                mIsPlaying = false;
                logEventForAudio("complete", path, "");
            });
            mMediaPlayer.setOnErrorListener((mp, what, extra) -> {
                logEventForAudio("error", mPath, String.format("what=%s, extra=%s", what, extra));
                reset();
                return false;
            });
            mMediaPlayer.prepareAsync();
            mIsPlaying = true;
            mPath = path;
        } catch (Exception e) {
            logEventForAudio("error", path, Log.getStackTraceString(e));
            reset();
            e.printStackTrace();
        }
        return mIsPlaying;
    }

    public boolean start(String path, OnStatusListener onStatusListener) {
        initPlayer();
        logEventForAudio("start", path, "");
        try {
            int streamType = AudioManager.STREAM_MUSIC;
            mAudioManager.requestAudioFocus(listener, streamType, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
            mMediaPlayer.setAudioStreamType(streamType);
            mMediaPlayer.setDataSource(path);
            mMediaPlayer.setOnPreparedListener(mp -> {
                if (onStatusListener != null) {
                    onStatusListener.OnPrepared(mp);
                }
                mMediaPlayer.start();
                if (onStatusListener != null) {
                    onStatusListener.OnPlaying(mp);
                }
                logEventForAudio("prepared", path, "");
            });
            mMediaPlayer.setOnCompletionListener(mp -> {
                if (onStatusListener != null) {
                    onStatusListener.onCompletion(mp);
                }
                mIsPlaying = false;
                logEventForAudio("complete", path, "");
            });
            mMediaPlayer.setOnErrorListener((mp, what, extra) -> {
                if (onStatusListener != null) {
                    onStatusListener.OnError(what + "", extra + "");
                }
                logEventForAudio("error", mPath, String.format("what=%s, extra=%s", what, extra));
                reset();
                return false;
            });
            mMediaPlayer.prepareAsync();
            mIsPlaying = true;
            mPath = path;
        } catch (Exception e) {
            reset();
            logEventForAudio("error", path, Log.getStackTraceString(e));
            e.printStackTrace();
            if (onStatusListener != null) {
                onStatusListener.OnError("exception", e.getLocalizedMessage());
            }
        }
        return mIsPlaying;
    }

    private void logEventForAudio(String status, String path, String detail) {
        LogEvent logEvent = new LogEvent("audio-stream");
        logEvent.putData("status", status);
        logEvent.putData("path", path);
        logEvent.putData("detail", detail);
        AppLogClient.Companion.getInstance().addLog(logEvent);
    }

    public void stop() {
        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
            mIsPlaying = false;
            mMediaPlayer.stop();
        }
    }

    public void pause() {
        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
            mIsPlaying = false;
            mMediaPlayer.pause();
        }
    }

    public void resume() {
        if (mMediaPlayer != null && !mMediaPlayer.isPlaying() && hasPlayFile()) {
            int streamType = AudioManager.STREAM_MUSIC;
            mAudioManager.requestAudioFocus(listener, streamType, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

            mMediaPlayer.start();
            mIsPlaying = true;
        }
    }

    public void release() {
        mPath = null;
        mIsPlaying = false;
        mAudioManager.abandonAudioFocus(listener);
        if (mMediaPlayer != null) {
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }

    private void reset() {
        mPath = null;
        mIsPlaying = false;
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
        }
    }

    public boolean isPlaying() {
        return mIsPlaying;
    }

    public boolean isPlaying(String path) {
        if (isSamePath(path)) {
            return mIsPlaying;
        }
        return false;
    }

    public boolean isSamePath(String path) {
        return !TextUtils.isEmpty(mPath) && TextUtils.equals(path, mPath);
    }

    public boolean hasPlayFile() {
        return !TextUtils.isEmpty(mPath);
    }

    public MediaPlayer getMediaPlayer() {
        return mMediaPlayer;
    }

    public int getDuration() {
        return mMediaPlayer.getDuration();
    }

    public int getCurrentPosition() {
        return mMediaPlayer.getCurrentPosition();
    }
}
